namespace YXShop.ExcelLite
{
    using System;
    using System.Collections;
    using System.Drawing;
    using System.Reflection;
    using System.Runtime.InteropServices;

    public class CellRange : AbstractRange, IEnumerable
    {
        private int firstColumn;
        private int firstRow;
        private int lastColumn;
        private int lastRow;

        internal CellRange(ExcelWorksheet parent) : base(parent)
        {
            this.lastRow = 0xffff;
            this.lastColumn = 0xff;
        }

        internal CellRange(ExcelWorksheet parent, int firstRow, int firstColumn, int lastRow, int lastColumn) : base(parent)
        {
            ExcelRowCollection.ExceptionIfRowOutOfRange(firstRow);
            ExcelColumnCollection.ExceptionIfColumnOutOfRange(firstColumn);
            ExcelRowCollection.ExceptionIfRowOutOfRange(lastRow);
            ExcelColumnCollection.ExceptionIfColumnOutOfRange(lastColumn);
            if (lastRow < firstRow)
            {
                throw new ArgumentOutOfRangeException("", lastRow, "Argument lastRow can't be smaller than firstRow.");
            }
            if (lastColumn < firstColumn)
            {
                throw new ArgumentOutOfRangeException("", lastColumn, "Argument lastColumn can't be smaller than firstColumn.");
            }
            this.firstRow = firstRow;
            this.firstColumn = firstColumn;
            this.lastRow = lastRow;
            this.lastColumn = lastColumn;
        }

        public void CopyTo(string topLeftCell)
        {
            this.CopyTo(base.Parent, topLeftCell);
        }

        public void CopyTo(int absoluteRow, int absoluteColumn)
        {
            this.CopyTo(base.Parent, absoluteRow, absoluteColumn);
        }

        public void CopyTo(ExcelWorksheet destinationWorksheet, string topLeftCell)
        {
            int num;
            int num2;
            PositionToRowColumn(topLeftCell, out num, out num2);
            this.CopyTo(destinationWorksheet, num, num2);
        }

        public void CopyTo(ExcelWorksheet destinationWorksheet, int absoluteRow, int absoluteColumn)
        {
            CellRange range;
            try
            {
                range = destinationWorksheet.Cells.GetSubrangeAbsolute(absoluteRow, absoluteColumn, absoluteRow + this.Height, absoluteColumn + this.Width);
            }
            catch (Exception)
            {
                throw new ArgumentException("Destination range is incorrectly specified.");
            }
            if (this.Overlaps(range))
            {
                throw new ArgumentException("Destination range can't overlap with source range.");
            }
            if (range.IsAnyCellMerged)
            {
                throw new ArgumentException("Destination range can't overlap with existing merged range.");
            }
            int num = absoluteRow - this.firstRow;
            int num2 = absoluteColumn - this.firstColumn;
            Hashtable hashtable = new Hashtable();
            CellRangeEnumerator readEnumerator = this.GetReadEnumerator();
            while (readEnumerator.MoveNext())
            {
                ExcelCell currentCell = readEnumerator.CurrentCell;
                ExcelCell cell2 = destinationWorksheet.Rows[readEnumerator.CurrentRow + num].AllocatedCells[readEnumerator.CurrentColumn + num2];
                cell2.Value = currentCell.Value;
                cell2.Style = currentCell.Style;
                CellRange mergedRange = currentCell.MergedRange;
                if (mergedRange != null)
                {
                    hashtable[mergedRange] = mergedRange;
                }
            }
            foreach (MergedCellRange range3 in hashtable.Values)
            {
                destinationWorksheet.Cells.GetSubrangeAbsolute(range3.firstRow + num, range3.firstColumn + num2, range3.lastRow + num, range3.lastColumn + num2).Merged = true;
            }
        }

        public override bool Equals(object obj)
        {
            CellRange range = (CellRange) obj;
            return ((((this.firstRow == range.firstRow) && (this.firstColumn == range.firstColumn)) && (this.lastRow == range.lastRow)) && (this.lastColumn == range.lastColumn));
        }

        internal void ExceptionIfRowColumnOutOfRange(int row, int column)
        {
            if (this.IsRowColumnOutOfRange(row, column))
            {
                throw new ArgumentException("Row or column index is invalid or out of required range.");
            }
        }

        internal void FixFirstRowIndex(int rowIndex, int offset)
        {
            this.firstRow = Math.Min(Math.Max(this.firstRow + offset, rowIndex), 0xffff);
        }

        internal void FixLastRowIndex(int rowIndex, int offset)
        {
            this.lastRow = Math.Min(Math.Max((int) (this.lastRow + offset), (int) (rowIndex - 1)), 0xffff);
        }

        public IEnumerator GetEnumerator()
        {
            return new CellRangeEnumerator(this, false);
        }

        public override int GetHashCode()
        {
            return (((this.firstRow ^ this.firstColumn) ^ this.lastRow) ^ this.lastColumn);
        }

        public CellRangeEnumerator GetReadEnumerator()
        {
            return new CellRangeEnumerator(this, true);
        }

        public CellRange GetSubrange(string firstCell, string lastCell)
        {
            int num;
            int num2;
            int num3;
            int num4;
            PositionToRowColumn(firstCell, out num, out num2);
            PositionToRowColumn(lastCell, out num3, out num4);
            return this.GetSubrangeAbsolute(num, num2, num3, num4);
        }

        public CellRange GetSubrangeAbsolute(int firstRow, int firstColumn, int lastRow, int lastColumn)
        {
            if (((firstRow < this.firstRow) || (firstRow > this.lastRow)) || ((firstColumn < this.firstColumn) || (lastColumn > this.lastColumn)))
            {
                throw new ArgumentException("Specified subrange must be within this cell range.");
            }
            return new CellRange(base.Parent, firstRow, firstColumn, lastRow, lastColumn);
        }

        public CellRange GetSubrangeRelative(int relativeRow, int relativeColumn, int width, int height)
        {
            int firstRow = this.firstRow + relativeRow;
            int firstColumn = this.firstColumn + relativeColumn;
            return this.GetSubrangeAbsolute(firstRow, firstColumn, (firstRow + height) - 1, (firstColumn + width) - 1);
        }

        internal bool IsRowColumnOutOfRange(int row, int column)
        {
            if (((row >= this.firstRow) && (row <= this.lastRow)) && ((column >= this.firstColumn) && (column <= this.lastColumn)))
            {
                return false;
            }
            return true;
        }

        public bool Overlaps(CellRange range)
        {
            return (((base.Parent == range.Parent) && this.SectionsOverlap(this.firstColumn, this.lastColumn, range.firstColumn, range.lastColumn)) && this.SectionsOverlap(this.firstRow, this.lastRow, range.firstRow, range.lastRow));
        }

        public static void PositionToRowColumn(string position, out int row, out int column)
        {
            bool flag;
            PositionToRowColumn(position, out row, out column, out flag);
            if (flag)
            {
                throw new ArgumentException("Position is not in format RowNameColumnName.");
            }
        }

        internal static void PositionToRowColumn(string position, out int row, out int column, out bool wrongFormat)
        {
            string name = position.Split(new char[] { '1', '2', '3', '4', '5', '6', '7', '8', '9' }, 2)[0];
            if ((name.Length == 0) || (name.Length == position.Length))
            {
                row = column = -1;
                wrongFormat = true;
            }
            else
            {
                string str2 = position.Remove(0, name.Length);
                row = ExcelRowCollection.RowNameToIndex(str2);
                column = ExcelColumnCollection.ColumnNameToIndex(name);
                wrongFormat = false;
            }
        }

        public static string RowColumnToPosition(int row, int column)
        {
            return (ExcelColumnCollection.ColumnIndexToName(column) + ExcelRowCollection.RowIndexToName(row));
        }

        private bool SectionsOverlap(int sectionAStart, int sectionAEnd, int sectionBStart, int sectionBEnd)
        {
            return ((sectionAEnd >= sectionBStart) && (sectionBEnd >= sectionAStart));
        }

        public override void SetBorders(MultipleBorders multipleBorders, Color lineColor, LineStyle lineStyle)
        {
            MergedCellRange mergedRange = this.MergedRange;
            if (mergedRange != null)
            {
                mergedRange.SetBorders(multipleBorders, lineColor, lineStyle);
            }
            else
            {
                for (int i = this.firstRow; i <= this.lastRow; i++)
                {
                    for (int j = this.firstColumn; j <= this.lastColumn; j++)
                    {
                        MultipleBorders borders = multipleBorders;
                        if (i < this.lastRow)
                        {
                            borders &= ~MultipleBorders.Bottom;
                        }
                        if (i > this.firstRow)
                        {
                            borders &= ~MultipleBorders.Top;
                        }
                        if (j < this.lastColumn)
                        {
                            borders &= ~MultipleBorders.Right;
                        }
                        if (j > this.firstColumn)
                        {
                            borders &= ~MultipleBorders.Left;
                        }
                        base.Parent.Rows[i].AllocatedCells[j].SetBorders(borders, lineColor, lineStyle);
                    }
                }
            }
        }

        public override string ToString()
        {
            if ((this.Width <= 1) && (this.Height <= 1))
            {
                return (ExcelColumnCollection.ColumnIndexToName(this.firstColumn) + ExcelRowCollection.RowIndexToName(this.firstRow));
            }
            return (ExcelColumnCollection.ColumnIndexToName(this.firstColumn) + ExcelRowCollection.RowIndexToName(this.firstRow) + ":" + ExcelColumnCollection.ColumnIndexToName(this.lastColumn) + ExcelRowCollection.RowIndexToName(this.lastRow));
        }

        public string EndPosition
        {
            get
            {
                return RowColumnToPosition(this.lastRow, this.lastColumn);
            }
        }

        public int FirstColumnIndex
        {
            get
            {
                return this.firstColumn;
            }
        }

        public int FirstRowIndex
        {
            get
            {
                return this.firstRow;
            }
        }

        public override string Formula
        {
            get
            {
                MergedCellRange mergedRange = this.MergedRange;
                if (mergedRange == null)
                {
                    throw new InvalidOperationException("Cell range has defined formula only if it is merged.");
                }
                return mergedRange.Formula;
            }
            set
            {
                MergedCellRange mergedRange = this.MergedRange;
                if (mergedRange != null)
                {
                    mergedRange.Formula = value;
                }
                else
                {
                    base.Parent.ParentExcelFile.ExceptionIfOverAffectedCellsLimit(this.Height * this.Width);
                    foreach (ExcelCell cell in this)
                    {
                        cell.Formula = value;
                    }
                }
            }
        }

        public int Height
        {
            get
            {
                return ((this.lastRow - this.firstRow) + 1);
            }
        }

        public RangeIndexingMode IndexingMode
        {
            get
            {
                if (this.Height == 1)
                {
                    return RangeIndexingMode.Horizontal;
                }
                if (this.Width == 1)
                {
                    return RangeIndexingMode.Vertical;
                }
                return RangeIndexingMode.Rectangular;
            }
        }

        public bool IsAnyCellMerged
        {
            get
            {
                IEnumerator readEnumerator = this.GetReadEnumerator();
                while (readEnumerator.MoveNext())
                {
                    if (((ExcelCell) readEnumerator.Current).MergedRange != null)
                    {
                        return true;
                    }
                }
                return false;
            }
        }

        public override bool IsStyleDefault
        {
            get
            {
                MergedCellRange mergedRange = this.MergedRange;
                if (mergedRange == null)
                {
                    throw new InvalidOperationException("Cell range has defined style only if it is merged.");
                }
                return mergedRange.IsStyleDefault;
            }
        }

        public ExcelCell this[int contextIndex]
        {
            get
            {
                switch (this.IndexingMode)
                {
                    case RangeIndexingMode.Rectangular:
                    {
                        int width = this.Width;
                        int num2 = contextIndex / width;
                        int num3 = contextIndex % width;
                        return this[num2, num3];
                    }
                    case RangeIndexingMode.Horizontal:
                        return this[0, contextIndex];

                    case RangeIndexingMode.Vertical:
                        return this[contextIndex, 0];
                }
                throw new Exception("Internal: Unknown indexing mode.");
            }
        }

        public ExcelCell this[string contextName]
        {
            get
            {
                int firstRow;
                int firstColumn;
                switch (this.IndexingMode)
                {
                    case RangeIndexingMode.Rectangular:
                        PositionToRowColumn(contextName, out firstRow, out firstColumn);
                        break;

                    case RangeIndexingMode.Horizontal:
                        firstRow = this.firstRow;
                        firstColumn = ExcelColumnCollection.ColumnNameToIndex(contextName);
                        break;

                    case RangeIndexingMode.Vertical:
                        firstRow = ExcelRowCollection.RowNameToIndex(contextName);
                        firstColumn = this.firstColumn;
                        break;

                    default:
                        throw new Exception("Internal: Unknown indexing mode.");
                }
                this.ExceptionIfRowColumnOutOfRange(firstRow, firstColumn);
                return base.Parent.Rows[firstRow].AllocatedCells[firstColumn];
            }
        }

        public ExcelCell this[int relativeRow, int relativeColumn]
        {
            get
            {
                int row = this.firstRow + relativeRow;
                int column = this.firstColumn + relativeColumn;
                this.ExceptionIfRowColumnOutOfRange(row, column);
                return base.Parent.Rows[row].AllocatedCells[column];
            }
        }

        public int LastColumnIndex
        {
            get
            {
                return this.lastColumn;
            }
        }

        public int LastRowIndex
        {
            get
            {
                return this.lastRow;
            }
        }

        public virtual bool Merged
        {
            get
            {
                return (this.MergedRange != null);
            }
            set
            {
                if (!this.Merged)
                {
                    if (value)
                    {
                        base.Parent.ParentExcelFile.ExceptionIfOverAffectedCellsLimit(this.Height * this.Width);
                        base.Parent.MergedRanges.Add(new MergedCellRange(this));
                    }
                }
                else if (!value)
                {
                    base.Parent.ParentExcelFile.ExceptionIfOverAffectedCellsLimit(this.Height * this.Width);
                    base.Parent.MergedRanges.Remove(this.MergedRange);
                }
            }
        }

        private MergedCellRange MergedRange
        {
            get
            {
                MergedCellRange mergedRange = (MergedCellRange) this[0, 0].MergedRange;
                if ((mergedRange == null) || ((mergedRange.Width == this.Width) && (mergedRange.Height == this.Height)))
                {
                    return mergedRange;
                }
                return null;
            }
        }

        public string StartPosition
        {
            get
            {
                return RowColumnToPosition(this.firstRow, this.firstColumn);
            }
        }

        public override CellStyle Style
        {
            get
            {
                MergedCellRange mergedRange = this.MergedRange;
                if (mergedRange == null)
                {
                    throw new InvalidOperationException("Cell range has defined style only if it is merged.");
                }
                return mergedRange.Style;
            }
            set
            {
                MergedCellRange mergedRange = this.MergedRange;
                if (mergedRange != null)
                {
                    mergedRange.Style = value;
                }
                else
                {
                    base.Parent.ParentExcelFile.ExceptionIfOverAffectedCellsLimit(this.Height * this.Width);
                    foreach (ExcelCell cell in this)
                    {
                        cell.Style = value;
                    }
                }
            }
        }

        public override object Value
        {
            get
            {
                MergedCellRange mergedRange = this.MergedRange;
                if (mergedRange == null)
                {
                    throw new InvalidOperationException("Cell range has defined value only if it is merged.");
                }
                return mergedRange.Value;
            }
            set
            {
                MergedCellRange mergedRange = this.MergedRange;
                if (mergedRange != null)
                {
                    mergedRange.Value = value;
                }
                else
                {
                    base.Parent.ParentExcelFile.ExceptionIfOverAffectedCellsLimit(this.Height * this.Width);
                    foreach (ExcelCell cell in this)
                    {
                        cell.Value = value;
                    }
                }
            }
        }

        public int Width
        {
            get
            {
                return ((this.lastColumn - this.firstColumn) + 1);
            }
        }
    }
}

